#include "data.h"
#include "color.h"
#include <iostream>

#define SIZE 4

Data::Data(){
    data = NULL;
    width = 0;
    height = 0;
}

Data::Data(const Data& _data){
    width = _data.getWidth();
    height = _data.getHeight();
    data = new unsigned char[width * height * 4];

    for(int i = 0; i < width * height * 4; i++)
        data[i] = _data.getData(i);
}

Data::Data(unsigned char* _data, int _w, int _h) : data(_data), width(_w), height(_h){
}

Data::Data(int _w, int _h) : width(_w), height(_h){
    data = new unsigned char[width * height * 4];

    for(int i = 0; i < width * height * 4; i++)
        data[i] = 0;
}

Data::~Data(){
}

void Data::setData(unsigned char *_data){
    data = _data;
}

void Data::setData(int _i, unsigned char _c){
    data[_i] = _c;
}

unsigned char *Data::getData() const{
    return data;
}

unsigned char Data::getData(int _i) const{
    return data[_i];
}

const Color Data::getData(int _i, int _j){
    int size = SIZE;
    int result = (_j * size * width) + (size * _i);


    if(size == 4) return Color(data[result], data[result + 1], data[result + 2], data[result + 3]);
    return Color(data[result], data[result + 1], data[result + 2]);
}

void Data::setData(int _i, int _j, const Color &_c){
    int size = SIZE;
    int result = (_j * size * width) + (size * _i);

    if(size == 4){
        data[result] = _c.red;
        data[result + 1] = _c.green;
        data[result + 2] = _c.blue;
        data[result + 3] = _c.alpha;
    }else{
        data[result] = _c.red;
        data[result + 1] = _c.green;
        data[result + 2] = _c.blue;
    }
}

void Data::setSize(int _w, int _h){
    width = _w;
    height = _h;
}

int Data::getWidth() const{
    return width;
}

int Data::getHeight() const{
    return height;
}

void Data::setAll(unsigned char *_data, int _w, int _h){
    data = _data;
    width = _w;
    height = _h;
}


int *subtractInt(Data _data1, Data _data2){
    int width, height;
    if(_data1.getWidth() < _data2.getWidth()) width = _data1.getWidth();
    else width = _data2.getWidth();
    if(_data1.getHeight() < _data2.getHeight()) height = _data1.getHeight();
    else height = _data2.getHeight();

    int *result = new int[width * height * 4];

    int k = 0;
    for(int i = 0; i < width; i++){
        for(int j = 0; j < height; j++){
            result[k] = (int)_data1.getData(k) - (int)_data2.getData(k);
            k++;
            result[k] = (int)_data1.getData(k) - (int)_data2.getData(k);
            k++;
            result[k] = (int)_data1.getData(k) - (int)_data2.getData(k);
            k++;
            result[k] = 255;
            k++;
        }
    }

    return result;
}

Data *add(Data _data1, int *_data2){
    int width, height;
    width = _data1.getWidth();
    height = _data1.getHeight();

    Data *result = new Data(width, height);

    Color color1;
    Color color2;
    int k = 0;
    int colorInt[3];
    for(int i = 0; i < width; i++){
        for(int j = 0; j < height; j++){
            colorInt[0] = _data1.getData(k) + _data2[k];
            k++;
            colorInt[1] = _data1.getData(k) + _data2[k];
            k++;
            colorInt[2] = _data1.getData(k) + _data2[k];
            k++;
            color2 = Color((double)colorInt[0], (double)colorInt[1], (double)colorInt[2]);
            k = k - 3;
            result->setData(k++, color2.red);
            result->setData(k++, color2.green);
            result->setData(k++, color2.blue);
            result->setData(k++, 255);
        }
    }

    return result;
}

Data *operator+(Data _data1, Data _data2){
    int width, height;
    if(_data1.getWidth() < _data2.getWidth()) width = _data1.getWidth();
    else width = _data2.getWidth();
    if(_data1.getHeight() < _data2.getHeight()) height = _data1.getHeight();
    else height = _data2.getHeight();

    Data *result = new Data(width, height);
    for(int i = 0; i < width; i++){
        for(int j = 0; j < height; j++){
            result->setData(i, j, _data1.getData(i, j) + _data2.getData(i, j));
        }
    }


    return result;
}

Data *operator-(Data _data1, Data _data2){
    int width, height;
    if(_data1.getWidth() < _data2.getWidth()) width = _data1.getWidth();
    else width = _data2.getWidth();
    if(_data1.getHeight() < _data2.getHeight()) height = _data1.getHeight();
    else height = _data2.getHeight();

    Data *result = new Data(width, height);
    for(int i = 0; i < width; i++){
        for(int j = 0; j < height; j++){
            result->setData(i, j, _data1.getData(i, j) - _data2.getData(i, j));
        }
    }


    return result;
}

Data *operator*(Data _data1, Data _data2){
    int width, height;
    if(_data1.getWidth() < _data2.getWidth()) width = _data1.getWidth();
    else width = _data2.getWidth();
    if(_data1.getHeight() < _data2.getHeight()) height = _data1.getHeight();
    else height = _data2.getHeight();

    Data *result = new Data(width, height);
    for(int i = 0; i < width; i++){
        for(int j = 0; j < height; j++){
            result->setData(i, j, _data1.getData(i, j) * _data2.getData(i, j));
        }
    }


    return result;
}

Data *operator/(Data _data1, Data _data2){
    int width, height;
    if(_data1.getWidth() < _data2.getWidth()) width = _data1.getWidth();
    else width = _data2.getWidth();
    if(_data1.getHeight() < _data2.getHeight()) height = _data1.getHeight();
    else height = _data2.getHeight();

    Data *result = new Data(width, height);
    for(int i = 0; i < width; i++){
        for(int j = 0; j < height; j++){
            result->setData(i, j, _data1.getData(i, j) / _data2.getData(i, j));
        }
    }


    return result;
}
